/******************************************************************/
/* 				MOLIPCSVR						*/
/* It is a molkernel thread 							*/
/* It handles MINIX IPC and process status 				*/
/******************************************************************/

#define _MULTI_THREADED
/*---------------------- LINUX HEADERS ---------------------------*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*---------------------- MINIX HEADERS ---------------------------*/
#include "../include/minix/config.h" 	
#include "../include/minix/endpoint.h"
#include "../include/minix/com.h"
#include "../../kernel/ipc.h"	

/* #include "../../kernel/config.h" 	*/
/* #include "../../kernel/const.h" 		*/
/* #include "../../kernel/type.h" 		*/

/*---------------------- MOL HEADERS -----------------------------*/
#include "../include/mol/molminix.h"
#define MOLDBG 1
#include "../include/mol/mollib.h"

#define _SYSTEM
#include "../include/mol/molerr.h" 

/*---------------------- MOLKERNEL HEADERS -------------------------*/
#include "molproc.h"
#include "svripc.h"
#include "molsystem.h"

extern struct kproc	kproc[NR_PROCS+NR_TASKS];	/* kernel process table */
extern pid_t		kpid;

int do_badrqst(ipc_t *pipc);

/*----------------------------------------- GLOBAL VARIABLES ---------------------------------*/
mol_proc_t  ipcs_proc;		/*  IPC server Process data		*/
ipc_t 		ipcs_ipc;		/*  IPC server  IPC struct		*/

/*----------------------------------------------------------*/
/*	IPC  SERVER THREAD FUNCTION	      */
/*----------------------------------------------------------*/
void *ipcsvr_thread(void *arg)
{
    int rcode;
    int rqst;

	MOLDEBUG("IPC SERVER THREAD Starting\n");

	init_ipcsvr();

	while (TRUE) 
		{
OLPRINT("\n\nWaiting Request message...\n");
		rcode = svr_rcv(&ipcs_ipc);
		if ( rcode < 0 )
			MOLERROR(" svr_rcv rcode=%d",rcode);

OLDEBUG("Request: code=%X spid=%d seq=%d\n",
			ipcs_ipc.molmsg.code,
			ipcs_ipc.molmsg.spid,
			ipcs_ipc.molmsg.seq);

        rqst 	= ipcs_ipc.molmsg.code; 
		switch(rqst)
           	{
          	case BIND:
				rcode = ipc_bind(&ipcs_ipc);
				break;
			case SENDREC:
				rcode = mol_mini_sendrec(&ipcs_ipc);
				break;
            case SEND:
				rcode = mol_mini_send(&ipcs_ipc);
				break;
            case RECEIVE:
				rcode = mol_mini_receive(&ipcs_ipc);
                break;
			case NOTIFY:
				rcode = mol_mini_notify(&ipcs_ipc);
                break;
            default:
				do_badrqst(&ipcs_ipc); 
                break;
            }
		}
		
	rcode = mol_ipc_end(&ipcs_ipc);
    return(rcode);
}	

/**===========================================================================*
*                             init_ipcsvr							                                  *
*===========================================================================**/
int init_ipcsvr(void)
{
	int rcode;
	mol_proc_t  *ipcspp;

OLDEBUG("Initializing ipcsver thread...\n");
	ipcspp = &ipcs_proc;
	ipcspp->p_pid = kpid;
	strncpy(ipcspp->p_name,"ipcsvr",P_NAME_LEN);
}

/*----------------------------------------------------------*/
/*			ipc_bind						*/
/* BIND request received from CONTAINER 				*/
/* Every MINIX process that was binded by molkernel		*/
/* must be binded with the IPC server before using any Minix*/
/* IPC primitive. The IPC Server store the process socket 	*/
/* address of the IPC Channel						*/
/*----------------------------------------------------------*/
int ipc_bind(ipc_t *pipc)
{
	int rcode;
	proc_nr_t  src_p;
	struct kproc *pptr;

OLDEBUG("code=%X spid=%d seq=%d p_nr=%d p_endpoint=%d\n",
                pipc->molmsg.code,
                pipc->molmsg.spid,
                pipc->molmsg.seq,
                pipc->molmsg.p_nr,
                pipc->molmsg.p_endpoint);
	
	/* Check sender's endpoint			 	*/
	src_p = check_endpoint(pipc->molmsg.p_endpoint);
	if( src_p == NONE )
		MOLERROR("Bad endpoint rcode=%d\n",src_p);
		
	pptr = &kproc[src_p+NR_TASKS];		

	/* Check if the sender is a registered process 	*/
	rcode = check_registered(pptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks for valid received sequence 		*/
	rcode = check_sequence(pptr, pipc);
	if( rcode != OK) return(rcode);

	/* Checks if the sender process is NOTREADY	*/
	rcode = check_notready(pptr, pipc);
	if( rcode != OK) return(rcode);
		
OLDEBUG("IPC Binding pid=%d p_endpoint=%d p_nr=%d p_name=%s \n",
		pptr->pid,
		pptr->p_endpoint,
		pptr->p_nr,
		pptr->p_name);

	/* Stores the process IPC channel socket address*/
	memcpy((void*) &pptr->ipc_addr,(void *)&pipc->addr,sizeof(struct sockaddr));
	
	/* Builds the reply					*/
	pipc->molmsg.code = (BIND | ACKNOWLEDGE);
	pipc->molmsg.p_nr = SYSTEM;
	pipc->molmsg.p_endpoint = pptr->p_endpoint;
	pipc->molmsg.seq  = pptr->kseq;
	pipc->molmsg.spid = kpid;
	rcode =svr_send(pipc);
	if( rcode != OK )
		MOLERROR("svr_send rcode=%d",rcode);  

	return (OK);	
}

		